package com.night.icm.service.core.service;

import com.github.wenhao.jpa.PredicateBuilder;
import com.github.wenhao.jpa.Specifications;
import com.night.icm.common.exception.LoginFailedException;
import com.night.icm.common.exception.NoSuchDataException;
import com.night.icm.common.jpa.PageHelper;
import com.night.icm.common.service.PageDataUtil;
import com.night.icm.common.utils.PageDataDTO;
import com.night.icm.model.core.UserDTO;
import com.night.icm.persistence.core.entity.User;
import com.night.icm.persistence.core.repository.UserRepository;
import com.night.icm.service.core.mapper.UserMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;

/**
 * UserServiceImpl
 *
 * @author Liao ZhiYong
 * @date 2019/12/10
 */
@Service
@Transactional(readOnly = true, rollbackFor = Exception.class)
public class UserServiceImpl implements UserService {

    private final UserRepository userRepository;
    private final UserMapper userMapper;
    private final BCryptPasswordEncoder bCryptPasswordEncoder;

    @Autowired
    public UserServiceImpl(UserRepository userRepository, UserMapper userMapper, BCryptPasswordEncoder bCryptPasswordEncoder) {
        this.userRepository = userRepository;
        this.userMapper = userMapper;
        this.bCryptPasswordEncoder = bCryptPasswordEncoder;
    }

    /**
     * 新建用户
     *
     * @param createInfo 新建数据
     * @return 用户信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserDTO createUser(UserDTO createInfo) {
        if (userRepository.findByUsername(createInfo.getUsername()) != null) {
            throw new BadCredentialsException("该用户已存在！The username is exited!");
        }
        createInfo.setPassword(bCryptPasswordEncoder.encode(createInfo.getPassword()));
        User user = userMapper.toEntity(createInfo);
        user = userRepository.save(user);
        return userMapper.toDTO(user);
    }

    /**
     * 分页查询用户信息
     *
     * @param page     页号，从0开始
     * @param size     每页纪录条数
     * @param sort     排序字段, 例如：字段1,asc,字段2,desc
     * @param username 用户名，支持模糊查询
     * @param role     角色名，支持模糊查询
     * @return 用户分页数据
     */
    @Override
    public PageDataDTO<UserDTO> findOnePage(int page, int size, String sort, String username, String role) {
        PredicateBuilder<User> pb = Specifications.<User>and()
                .like(StringUtils.isNotBlank(username), "username", "%" + username + "%")
                .eq(StringUtils.isNotBlank(role), "role", role);
        Page<User> entity = this.userRepository.findAll(pb.build(), PageHelper.generatePageRequest(page, size, sort));
        List<UserDTO> doList = this.userMapper.toList(entity.getContent());
        return PageDataUtil.toPageData(entity, doList);
    }

    /**
     * 根据id删除用户
     *
     * @param id 用户id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteById(String id) {
        this.userRepository.deleteById(Integer.valueOf(id));
    }

    /**
     * 更新用户信息
     *
     * @param id      用户id
     * @param userDTO 用户信息
     * @return 更新后用户信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserDTO update(String id, UserDTO userDTO) {
        Optional<User> optional = this.userRepository.findById(Integer.valueOf(id));
        if (!optional.isPresent()) {
            throw new NoSuchDataException(id);
        }
        User user = optional.get();
        this.userMapper.updateEntity(userDTO, user);
        user.setPassword(bCryptPasswordEncoder.encode(userDTO.getPassword()));
        this.userRepository.save(user);
        return this.userMapper.toDTO(user);
    }

    /**
     * 查找所有用户
     *
     * @return userDTO
     */
    @Override
    public List<UserDTO> findAll() {
        List<User> entitys = this.userRepository.findAll();
        return this.userMapper.toList(entitys);
    }

    /**
     * 通过Id查找用户
     *
     * @param id userID
     * @return user
     */
    @Override
    public UserDTO findById(String id) {
        Optional<User> entity = this.userRepository.findById(Integer.valueOf(id));
        if (!entity.isPresent()) {
            throw new NoSuchDataException(id);
        }
        return this.userMapper.toDTO(entity.get());
    }

    /**
     * 通过用户名name查找用户
     *
     * @param name 用户名
     * @return 用户
     */
    @Override
    public UserDTO findByName(String name) {
        User user = this.userRepository.findByUsername(name);
        return this.userMapper.toDTO(user);
    }

    /**
     * 修改用户密码
     *
     * @param id          用户id
     * @param oldPassword 原密码
     * @param newPassword 新密码
     * @return 是否成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateUserPassword(String id, String oldPassword, String newPassword) {
        Optional<User> user = this.userRepository.findById(Integer.valueOf(id));
        if (!user.isPresent()) {
            throw new NoSuchDataException(id);
        }
        User user1 = user.get();
        if (bCryptPasswordEncoder.matches(oldPassword, user1.getPassword())) {
            user1.setPassword(bCryptPasswordEncoder.encode(newPassword));
            this.userRepository.save(user1);
            return true;
        } else {
            throw new LoginFailedException("原密码输入错误!");
        }
    }
}